﻿//
// Created by huiyi on 12/15/22.
//

#ifndef REF_TEST_REF_HPP
#define REF_TEST_REF_HPP

#include <map>
#include <string>

//向前声明
struct RefModelInfo;struct RefModelMemberInfo;
typedef bool(*RefBaseModelFunc)(void*ModelPtr,const char*RefData);

/*
 需要记录：简单类型，结构体，类，等
 简单类型比较好实现
 结构体里面可以嵌套变量和类,方法等
 类里面会嵌套变量与方法等

 理想状态下的实现:

 ===================
 //注册模型,返回模型句柄
 1.注册模型
    1).基础反射类型(int,bool),不需要特殊处理的类(例如CXTextA,std::vector)等
        modelHandle = RefModelRegBase(type,refFunc);
    2).如果为嵌套类型,例如结构体
        //先注册结构体
        modelHandle = RefModelRegStruct(type);
        //结构体添加成员信息
        //type为原型,member为type下的成员,函数应该自行计算成员偏移量(一般使用宏生成代码),可使用#var反射成员名称
        RefModelStructAddMember(modelHandle,type,member);
 2.注册
    1).反射结构与其显式别名应区分开,即:
        注册模型
        申请别名
        别名->模型

*/


// 需要有一个哈希表
// 绑定变量类型名称与类型信息
// std::map<变量类型名称,类型信息>
inline std::map<std::string,RefModelInfo*> g_RefModeRegister;

//定义模型类型
//基础类型和嵌套类型
enum RefModelType {
    Bases=0,
    Nesting=1,
};

/*
 * 类型信息
 * 需要记录:
 *  模型类型:为基础类型或者嵌套类型,又或者类等
 *  模型总尺寸:结构体的总尺寸
 *  类型名称:模型的类型名称
 *  反射函数：作用到此时,触发反射函数 bool(void*ModelPtr,const char*RefData)
 * */
struct RefModelInfo {
    //RefModelType type;  //模型类型
    bool isNesting; //是否为嵌套类型
    int size;  //模型总尺寸
    std::string typeName;//类型名称
    void* refFunc; //反射函数
    //如果是嵌套类型,此map用以记录反射名称与对应的类型,类型可以是已注册的任何类型(除了自身,防止死锁)
    // map<显式反射名称,成员类型>
    std::map<std::string,RefModelMemberInfo*> memberMap;
};
//反射模型的成员结构
struct RefModelMemberInfo {
    std::string typeName;
    int deviation; //成员在当前结构体的偏移
};

//模型句柄类型
typedef RefModelInfo* RefModelHandle;

//注册基础反射模型
inline RefModelHandle RefRegBaseModelEx(const char* typeName, int size,void* refFunc) {
    //如果已经注册则返回已注册的信息
    auto regModel = g_RefModeRegister.find(typeName);
    if (regModel!=g_RefModeRegister.end()) {
        return regModel->second;
    }
    //如果未注册则进行注册
    auto tmp = new RefModelInfo;
    tmp->isNesting=false;
    tmp->refFunc=refFunc;
    tmp->size=size;
    tmp->typeName=typeName;
    g_RefModeRegister[typeName]=tmp;
    return tmp;
}
//宏包装版本
#define RefModelRegBase(type,func) RefRegBaseModelEx(typeid(type).name(), sizeof(type),func);

inline bool RefFillDataEx (void* ptr,const char*typeName,const char*data) {
    auto mr = g_RefModeRegister.find(typeName);
    if (mr == g_RefModeRegister.end()){
        std::string r="RefFillBaseData: 类型 ";
        r+=typeName;
        r+=" 未注册";
        throw std::exception(r.c_str());
        return false;
    }
    auto rFunc = (RefBaseModelFunc)mr->second->refFunc;
    if (rFunc!=nullptr){
        rFunc(ptr,data);
    }
    return true;
};


//嵌套类型关联
//std::map<std::string,RefModelInfo*> g_RefNestingModeRegister;

//注册嵌套反射模型
inline RefModelHandle RefRegNestingModelEx(const char* typeName, int size) {
    //如果已经注册则返回已注册的信息
    auto regModel = g_RefModeRegister.find(typeName);
    if (regModel!=g_RefModeRegister.end()) {
        return regModel->second;
    }
    //如果未注册则进行注册
    auto tmp = new RefModelInfo;
    tmp->isNesting=true;
    tmp->refFunc=nullptr;
    tmp->size=size;
    tmp->typeName=typeName;
    g_RefModeRegister[typeName]=tmp;
    return tmp;
};
//宏包装版本
#define RefRegNestingModel(type) RefRegNestingModelEx(typeid(type).name(), sizeof(type));

//嵌套类型注册成员
inline bool RefNestingModelRegMember(RefModelHandle handle, //注册的句柄
                                     const char*refName,    //反射的显式名称
                                     const char* refType,   //反射的类型名称,必须为已注册的类型
                                     int deviation          //成员在结构体的偏移地址
                                     ) {
    if (handle==nullptr){
        throw std::exception("RefNestingModelRegMember: 模型句柄不能为NULL");
        return false;
    }
    if (!handle->isNesting){
        throw std::exception("RefNestingModelRegMember: 句柄指向模型不为结构体模型");
        return false;
    }
    //检查显式反射名是否已注册
    auto memberIterator = handle->memberMap.find(refName);
    if (memberIterator!=handle->memberMap.end()) {
        std::string r="RefNestingModelRegMember: 欲注册成员 ";
        r+=refName;
        r+=" 已存在";
        throw std::exception(r.c_str());
        return false;
    }
    //检查欲反射的类型是否已注册
    auto modelIterator = g_RefModeRegister.find(refType);
    if (modelIterator==g_RefModeRegister.end()) {
        std::string r="RefNestingModelRegMember: 欲注册成员 ";
        r+=refName;
        r+=" 的类型是 ";
        r+=refType;
        r+=" 但是此类型未注册";
        throw std::exception(r.c_str());
        return false;
    }
    auto memberInfo = new RefModelMemberInfo;
    memberInfo->typeName=refType;
    memberInfo->deviation=deviation;

    handle->memberMap[refName]=memberInfo;
    return true;
}


#include "refRegister.hpp"


#endif //REF_TEST_REF_HPP
